package toponet.overlay;

import java.util.Enumeration;

import sicsim.network.core.Bandwidth;
import sicsim.network.core.FailureDetector;
import sicsim.network.core.Monitor;
import sicsim.network.core.OverlayNetwork;
import sicsim.network.links.AbstractLink;
import sicsim.network.peers.AbstractPeer;
import sicsim.network.peers.PeerEventListener;
import sicsim.types.Message;
import sicsim.types.NodeId;
import toponet.geometry.Point;

// OK it won't be so mobile but nevermind...

public class MobilePeer extends AbstractPeer {
	private Point location;
	private boolean available;
	private NodeId fln = null;
	private double min_dist;
	// Initialize the node an
	public void init(NodeId nodeId, AbstractLink link, Bandwidth bandwidth, FailureDetector failureDetector, OverlayNetwork overlay, Monitor monitor) {
		super.init(nodeId, link, bandwidth, failureDetector, overlay, monitor);
		this.location = this.getRandomLocation();
		this.available = true;
	}
		
	@Override
	public void create(long currentTime) {
		// TODO Auto-generated method stub
		this.overlay.add(this.nodeId);
	}

	@Override
	public void join(long currentTime) {
		// TODO Auto-generated method stub
		System.out.println("JOIN mobile node");
		this.broadcast(new Message("MOBILOCASK", this.location.getX()+"&"+this.location.getY()));
		this.overlay.add(this.nodeId);
	}

	@Override
	public void leave(long currentTime) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void failure(NodeId failedId, long currentTime) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void receive(NodeId srcId, Message msg, long currentTime) {
		// TODO Auto-generated method stub
		if (this.listeners.containsKey(msg.type))
			this.listeners.get(msg.type).receivedEvent(srcId, msg);
		//else
			//System.out.println("MOBPEER: I'm node " + this.nodeId + " and event " + msg.type + " is not registered!");
	}

	@Override
	public void signal(int signal, long currentTime) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void syncMethod(long currentTime) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void restore(String status) {
		// TODO Auto-generated method stub
		
	}

	@Override
	protected void registerEvents() {
		this.addEventListener("LOCRESP", new PeerEventListener() {
			public void receivedEvent(NodeId srcId, Message msg) {
				handleLocationResponseEvent(srcId, msg);
			}
		});
	}

	private void handleLocationResponseEvent(NodeId srcId, Message msg) {
		System.out.println("Node "+srcId+" has distance "+msg.data+" from "+this.nodeId);
		if(this.fln == null) {
			System.out.println("FIRST CLOSEST FOR "+this.nodeId+" and is "+srcId);
			this.fln = srcId;
			this.min_dist = Double.parseDouble(msg.data);
			this.sendMsg(srcId, new Message("MOBIJOIN", this.location.getX()+"&"+this.location.getY()));
		}
		else {
			if(this.min_dist > Double.parseDouble(msg.data)) {
				System.out.println("CLOSEST NODE CHANGED FOR "+this.nodeId+" and is "+srcId);
				this.sendMsg(this.fln, new Message("MOBIDELME", ""));
				this.fln = srcId;
				this.min_dist = Double.parseDouble(msg.data);
				this.sendMsg(srcId, new Message("MOBIJOIN", this.location.getX()+"&"+this.location.getY()));
			}
		}
	}

	private Point getRandomLocation() {
		return new Point(Math.random()%0.1+23.6914 , Math.random()%0.1+37.9634);
	}
	
	private boolean isAvailable() {
		return this.available;
	}
	
	private synchronized void occupy() throws AvailabilityException{
		if(!this.available)
			throw new AvailabilityException();
		this.available = false;
	}
	
	private synchronized void release() throws AvailabilityException{
		if(this.available)
			throw new AvailabilityException();
		this.available = true;
	}
	
	public Point getLocation() {
		return this.location;
	}
	
	public NodeId getFirstLevelNode() {
		return this.fln;
	}
}
